<?php

namespace app\api\traits;

use think\exception\ValidateException;
use think\Validate;

trait ValidateTrait
{
    /**
     * 增强型场景验证
     * @param string $scene 场景名称
     * @param array $data 验证数据
     * @param bool $batch 是否批量验证
     * @return array
     * @throws ValidateException
     */
    protected function autoValidate(
        string $scene,
        array $data = [],
        bool $batch = false
    ): array
    {
        $config = $this->parseSceneConfig($scene);

        $validator = new Validate();
        $validator->rule($config['rules'])
            ->message(array_merge($this->getMessages(), $config['messages']))
            ->field($config['attributes']);

        if ($batch) {
            $validator->batch(true);
        }

        $data = $data ?: request()->param();

        if (!$validator->check($data)) {
            $errors = (array)$validator->getError();
            // 优化点1：清理消息末尾标点
            $errorMsg = implode(', ', array_map(function ($v) {
                return rtrim($v, ',，');
            }, $errors));

            throw new ValidateException($errorMsg);
        }

        return $data;
    }

    /**
     * 场景配置解析器（支持10种配置格式）
     */
    private function parseSceneConfig(string $scene): array
    {
        // 防御性编程：检查必要属性
        if (!property_exists($this, 'validationScenes')) {
            throw new ValidateException("validation.scenes");
        }

        $scenes = $this->validationScenes;

        // 场景存在性检查
        if (!isset($scenes[$scene])) {
            throw new ValidateException("验证场景[{$scene}]未定义");
        }

        $rules = [];
        $attributes = [];
        $messages = [];
        $globalAttributes = $this->validationAttributes ?? [];

        foreach ($scenes[$scene] as $field => $config) {
            // +++ 新增优化点：强化索引数组处理 +++
            if (is_array($config) && isset($config[0]) && isset($config[1])) {
                $ruleStr = is_string($config[0]) ? explode('|', $config[0]) : $config[0];
                $fieldName = $config[1]; // 直接使用场景配置中的字段别名
                $sceneMessages = $config[2] ?? [];

                // 规则处理
                $rules[$field] = $this->normalizeRule($ruleStr);

                // 字段别名（优先使用场景配置，不再依赖全局validationAttributes）
                $attributes[$field] = $fieldName;

                // 自动生成规则级消息键
                foreach ($ruleStr as $ruleItem) {
                    $ruleName = explode(':', $ruleItem)[0];
                    if (isset($this->getMessages()[$ruleName])) {
                        $msgKey = "{$field}.{$ruleName}";
                        // 优先使用场景消息，其次自动替换全局模板
                        if (!isset($sceneMessages[$ruleName])) {
                            $messages[$msgKey] = str_replace(
                                [':attribute', ':rule'],
                                [$fieldName, explode(':', $ruleItem)[1] ?? ''],
                                $this->getMessages()[$ruleName]
                            );
                        } else {
                            $messages[$msgKey] = $sceneMessages[$ruleName];
                        }
                    }
                }
                continue;
            }

            // 处理完整数组配置（支持5种子格式）
            if (is_array($config)) {
                // 规则提取（支持索引数组和关联数组）
                $rule = $config['rule'] ?? $config[0] ?? '';

                // 闭包规则特殊处理
                if ($rule instanceof \Closure) {
                    $rules[$field] = $rule;
                } else {
                    $rules[$field] = $this->normalizeRule($rule);
                }

                // 字段别名处理（支持全局和场景专用）
                $attributes[$field] = $config['name'] ?? $config[1] ?? $globalAttributes[$field] ?? $field;

                // 消息处理（支持字段级和规则级消息）
                if (isset($config['message']) || isset($config[2])) {
                    $message = $config['message'] ?? $config[2];

                    // 处理多维消息数组
                    if (is_array($message)) {
                        foreach ($message as $ruleName => $msg) {
                            $key = "{$field}.{$ruleName}";
                            $messages[$key] = $msg;
                        }
                    } else {
                        // 自动关联首条规则
                        $firstRule = $this->getFirstRuleName($rules[$field]);
                        if ($firstRule) {
                            $messages["{$field}.{$firstRule}"] = $message;
                        }
                    }
                }
            }
        }

        return [
            'rules' => $rules,
            'attributes' => $attributes,
            'messages' => $messages
        ];
    }

    /**
     * 规则标准化处理器（支持8种规则格式）
     */
    private function normalizeRule($rule)
    {
        // 保留闭包规则
        if ($rule instanceof \Closure) {
            return $rule;
        }

        // 处理数组规则（包括关联数组）
        if (is_array($rule)) {
            $processed = [];
            foreach ($rule as $key => $value) {
                // 处理关联数组规则（如 ['in' => [1,2,3], 'between' => '1,100']）
                if (!is_numeric($key)) {
                    $param = is_array($value) ? implode(',', $value) : $value;
                    $processed[] = "{$key}:{$param}";
                } else {
                    // 处理索引数组元素（如 ['require', 'max:20']）
                    $processed[] = $value;
                }
            }
            return implode('|', $processed);
        }

        // 处理字符串规则（自动转换数组格式）
        if (is_string($rule)) {
            return strpos($rule, '|') !== false ? explode('|', $rule) : $rule;
        }

        return $rule;
    }

    /**
     * 获取首条规则名称（用于消息自动关联）
     */
    private function getFirstRuleName($rule): string
    {
        if ($rule instanceof \Closure) {
            return 'closure';
        }

        if (is_array($rule)) {
            $first = $rule[0] ?? '';
            return is_string($first) ? explode(':', $first)[0] : '';
        }

        if (is_string($rule)) {
            return explode(':', $rule)[0];
        }

        return '';
    }

    /**
     * 增强型验证消息模板（包含36种常见规则）
     */
    private function getMessages(): array
    {
        // 映射到语言包键名
        return [
            'require' => 'validation.require',
            'accepted' => 'validation.accepted',
            'date' => 'validation.date',
            'number' => 'validation.number',
            'integer' => 'validation.integer',
            'float' => 'validation.float',
            'boolean' => 'validation.boolean',
            'array' => 'validation.array',
            'object' => 'validation.object',
            'email' => 'validation.email',
            'mobile' => 'validation.mobile',
            'idCard' => 'validation.idCard',
            'zip' => 'validation.zip',
            'url' => 'validation.url',
            'ip' => 'validation.ip',
            'dateFormat' => 'validation.dateFormat',
            'regex' => 'validation.regex',
            'in' => 'validation.in',
            'notIn' => 'validation.notIn',
            'between' => 'validation.between',
            'notBetween' => 'validation.notBetween',
            'length' => 'validation.length',
            'max' => 'validation.max',
            'min' => 'validation.min',
            'confirm' => 'validation.confirm',
            'different' => 'validation.different',
            'eq' => 'validation.eq',
            'gt' => 'validation.gt',
            'egt' => 'validation.egt',
            'lt' => 'validation.lt',
            'elt' => 'validation.elt',
            'file' => 'validation.file',
            'image' => 'validation.image',
            'fileSize' => 'validation.fileSize',
            'fileExt' => 'validation.fileExt',
            'fileMime' => 'validation.fileMime',
            'unique' => 'validation.unique',
            'exist' => 'validation.exist',
            'filter' => 'validation.filter',
            'behavior' => 'validation.behavior',
            'json' => 'validation.json',
            'token' => 'validation.token'
        ];

    }
}
